using System;
using System.IO;
using System.Text;
using System.Globalization;

using System.Collections;
using System.Collections.Generic;

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

using Microsoft.TeamFoundation.VersionControl.Client;

using CSharpDistilled.Diagnostics;
using CSharpDistilled.Diagnostics.Providers;

namespace CSharpDistilled.Diagnostics.TeamFoundation
{
    /// <summary>
    /// Provides an additional check-in policy within Microsoft Team Foundation Server to ensure that all catch blocks within C# and VB code contain 
    /// appropriate calls to the <see cref="T:CSharpDistilled.Diagnostics.Providers.ExceptionProvider"/> class.
    /// </summary>
    [Serializable]
    public sealed class ExceptionProviderPolicy : PolicyBase
    {
        #region ExceptionProviderPolicy Private Fields

        private const string CATCH = "catch";
        private const string PROVIDER = "ExceptionProvider.Publish";

        #endregion

        #region public ExceptionProviderPolicy() : base()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ExceptionProviderPolicy"/> class.    
        /// </summary>
        public ExceptionProviderPolicy() : base()
        {

        }

        #endregion

        #region public override void Initialize(IPendingCheckin pendingCheckin)

        /// <summary>
        /// Initializes the specified pending checkin.
        /// </summary>
        /// <param name="pendingCheckin">The pending checkin.</param>
        public override void Initialize(IPendingCheckin pendingCheckin)
        {
            base.Initialize(pendingCheckin);
        }

        #endregion

        #region private void PendingChanges_CheckedPendingChangesChanged(object sender, EventArgs e)

        /// <summary>
        /// Handles the CheckedPendingChangesChanged event of the PendingChanges control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.NotImplementedException.#ctor(System.String)"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private void PendingChanges_CheckedPendingChangesChanged(object sender, EventArgs e)
        {
            throw new NotImplementedException("The method or operation is not implemented.");
        }

        #endregion

        #region protected override void OnPolicyStateChanged(PolicyFailure[] failures)

        /// <summary>
        /// Called when the policy state changed.
        /// </summary>
        /// <param name="failures">The policy failures.</param>
        protected override void OnPolicyStateChanged(PolicyFailure[] failures)
        {
            base.OnPolicyStateChanged(failures);
        }

        #endregion

        #region public override void Activate(PolicyFailure failure)

        /// <summary>
        /// Called if the user double-clicks on a policy failure.
        /// </summary>
        /// <param name="failure">The policy failure.</param>
        public override void Activate(PolicyFailure failure)
        {
            base.Activate(failure);
        }

        #endregion

        #region public override void DisplayHelp(PolicyFailure failure)

        /// <summary>
        /// Called if F1 is pressed when a policy failure is active on the user's display.
        /// </summary>
        /// <param name="failure">The policy failure.</param>
        public override void DisplayHelp(PolicyFailure failure)
        {
            base.DisplayHelp(failure);
        }

        #endregion

        #region public override string Description

        /// <summary>
        /// Gets the description of this policy.
        /// </summary>
        /// <value>The policy description.</value>
        public override string Description
        {
            get 
            {
                return SR.GetString(SR.Description);
            }
        }

        #endregion

        #region public override bool CanEdit

        /// <summary>
        /// Gets a value indicating whether or not this policy includes configuration UI. <c>true</c> if the policy includes configuration UI; otherwise <c>false</c>.
        /// </summary>
        /// <value><c>true</c> if this instance can edit; otherwise, <c>false</c>.</value>
        public override bool CanEdit
        {
            get
            {
                return false;
            }
        }

        #endregion

        #region public override bool Edit(IPolicyEditArgs policyEditArgs)

        /// <summary>
        /// Used to show a dialog or other UI to the user to specify options for the check-in policy.
        /// </summary>
        /// <param name="policyEditArgs">The policy edit args.</param>
        /// <returns></returns>
        public override bool Edit(IPolicyEditArgs policyEditArgs)
        {
            return true;
        }

        #endregion

        #region public override PolicyFailure[] Evaluate()

        /// <summary>
        /// Performs the actual policy evaluation.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// Called by the policy framework when a policy evaluation is required.
        /// </remarks>
        public override PolicyFailure[] Evaluate()
        {
            int index = 0;

            List<PolicyFailure> failures = new List<PolicyFailure>();

            foreach (PendingChange change in this.PendingCheckin.PendingChanges.AllPendingChanges)
            {
                if (change.FileName.EndsWith(".cs"))
                {
                    string source = File.ReadAllText(change.LocalItem);

                    do
                    {
                        // search the C# code for a catch statement.
                        index = source.IndexOf(CATCH);

                        int openingBrace = source.IndexOf("{", index);
                        int closingBrace = source.IndexOf("}", openingBrace);

                        string catchBlock = source.Substring(openingBrace, closingBrace - openingBrace);

                        StringBuilder traceBuilder = new StringBuilder(change.LocalItem);

                        if (catchBlock.Contains(PROVIDER))
                        {
                            traceBuilder.Append(" contains exception publication code at index ");
                        }
                        else
                        {
                            traceBuilder.Append(" contains a catch block without appropriate exception publication code at index ");

                            failures.Add(new PolicyFailure(SR.GetString(SR.PolicyFailure), this));
                        }

                        traceBuilder.Append(index.ToString(CultureInfo.CurrentCulture));
                        traceBuilder.Append(".");

                        Trace.WriteLine(traceBuilder.ToString());
                    }
                    while (index != -1);
                }
            }

            return failures.ToArray();
        }

        #endregion

        #region public override string Type

        /// <summary>
        /// Gets the string to describe this policy.
        /// </summary>
        /// <value>The type.</value>
        public override string Type
        {
            get 
            {
                return SR.GetString(SR.Type);
            }
        }
 
        #endregion

        #region public override string TypeDescription

        /// <summary>
        /// Gets the description of this type of policy.
        /// </summary>
        /// <value>The type description.</value>
        public override string TypeDescription
        {
            get 
            {
                return SR.GetString(SR.TypeDescription);
            }
        } 

        #endregion

        #region public override string InstallationInstructions

        /// <summary>
        /// Gets the installation instructions associated with this policy.
        /// </summary>
        /// <value>The installation instructions.</value>
        public override string InstallationInstructions
        {
            get
            {
                return SR.GetString(SR.InstallationInstructions);
            }
        }

        #endregion
    }
}
